from flask import Blueprint, jsonify, request, Response
from models import PurchaseMaster, PurchaseDetail
from extensions import db, redis_client
from flask_login import login_required
import csv
from io import StringIO
from sqlalchemy import text

purchases_bp = Blueprint('purchases', __name__)

import logging
import json
from decimal import Decimal

logging.basicConfig(level=logging.DEBUG)


class DecimalEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, Decimal):
            return str(obj)
        return super(DecimalEncoder, self).default(obj)


# 采购主表的CRUD操作
@purchases_bp.route('/purchases', methods=['GET'])
@login_required
def get_purchases():
    try:
        logging.debug('Attempting to fetch purchases from Redis cache')
        cached_purchases = redis_client.get('purchases')
        if cached_purchases:
            logging.debug('Found purchases in Redis cache')
            serialized_purchases = json.loads(cached_purchases)
        else:
            logging.debug('No purchases found in Redis cache, querying database')
            purchases = PurchaseMaster.query.all()
            if not purchases:
                logging.debug('No purchases found in the database')
            serialized_purchases = []
            for purchase in purchases:
                purchase_dict = purchase.to_dict()
                purchase_dict['details'] = [detail.to_dict() for detail in purchase.details]
                serialized_purchases.append(purchase_dict)
            logging.debug('Setting purchases in Redis cache')
            redis_client.set('purchases', json.dumps(serialized_purchases, cls=DecimalEncoder), ex=3600)  # Cache for 1 hour
        return jsonify(serialized_purchases), 200
    except Exception as e:
        logging.error(f'Error fetching purchases: {e}')
        return jsonify({'error': str(e)}), 400


@purchases_bp.route('/purchases/<int:id>', methods=['GET'])
@login_required
def get_purchase(id):
    try:
        purchase = PurchaseMaster.query.get_or_404(id)
        serialized_purchase = purchase.to_dict()
        return jsonify(serialized_purchase), 200
    except Exception as e:
        return jsonify({'error': '采购记录不存在'}), 400


@purchases_bp.route('/purchases', methods=['POST'])
@login_required
def create_purchase():
    try:
        data = request.get_json()
        existing_purchase = PurchaseMaster.query.filter_by(id=data.get('id')).first()
        if existing_purchase:
            return jsonify({'error': '该清单号已存在，请勿重复添加'}), 409  # HTTP 409 Conflict

        new_purchase = PurchaseMaster(
            id=data.get('id'),
            employee_id=data.get('employee_id'),
            quantity=data.get('quantity'),
            total_price=data.get('total_price'),
            purchase_time=data.get('purchase_time'),
            remark=data.get('remark')
        )
        db.session.add(new_purchase)
        db.session.commit()

        redis_client.delete('purchases')

        return jsonify(new_purchase.to_dict()), 201
    except Exception as e:
        return jsonify({'error': str(e)}), 400


@purchases_bp.route('/purchases/<int:purchase_id>', methods=['PUT'])
@login_required
def update_purchase(purchase_id):
    try:
        purchase = PurchaseMaster.query.get_or_404(purchase_id)
        data = request.get_json()

        new_purchase_id = data.get('new_id')
        if new_purchase_id and new_purchase_id != purchase_id:
            existing_purchase = PurchaseMaster.query.filter_by(id=new_purchase_id).first()
            if existing_purchase:
                return jsonify({'error': '新的采购清单号已存在，请选择不同的编号'}), 409  # HTTP 409 Conflict
            purchase.id = new_purchase_id

        purchase.employee_id = data.get('employee_id', purchase.employee_id)
        purchase.quantity = data.get('quantity', purchase.quantity)
        purchase.total_price = data.get('total_price', purchase.total_price)
        purchase.purchase_time = data.get('purchase_time', purchase.purchase_time)
        purchase.remark = data.get('remark', purchase.remark)
        db.session.commit()

        redis_client.delete('purchases')

        return jsonify(purchase.to_dict()), 200
    except Exception as e:
        return jsonify({'error': str(e)}), 400


@purchases_bp.route('/purchases/<int:purchase_id>', methods=['DELETE'])
@login_required
def delete_purchase(purchase_id):
    try:
        purchase = PurchaseMaster.query.get(purchase_id)
        if not purchase:
            return jsonify({'error': '采购清单号不存在'}), 404

        purchase_details = PurchaseDetail.query.filter_by(list_id=purchase_id).all()
        for detail in purchase_details:
            db.session.delete(detail)

        db.session.delete(purchase)
        db.session.commit()

        redis_client.delete('purchases')

        return jsonify({'message': '采购信息删除成功'}), 200
    except Exception as e:
        return jsonify({'error': str(e)}), 400


# 采购明细表的CRUD操作
@purchases_bp.route('/purchases/<int:purchase_id>/details/<int:detail_id>', methods=['GET'])
@login_required
def get_purchase_detail(purchase_id, detail_id):
    try:
        purchase_detail = PurchaseDetail.query.filter_by(list_id=purchase_id, id=detail_id).first_or_404()
        serialized_detail = purchase_detail.to_dict()
        return jsonify(serialized_detail), 200
    except Exception as e:
        return jsonify({'error': '采购明细记录不存在'}), 400


@purchases_bp.route('/purchases/<int:purchase_id>/details', methods=['POST'])
@login_required
def create_purchase_detail(purchase_id):
    try:
        purchase_master = PurchaseMaster.query.get_or_404(purchase_id)
        data = request.get_json()

        existing_detail = PurchaseDetail.query.filter_by(id=data.get('id')).first()
        if existing_detail:
            return jsonify({'error': '该明细号已存在，请勿重复添加'}), 409  # HTTP 409 Conflict

        new_detail = PurchaseDetail(
            id=data.get('id'),
            list_id=purchase_master.id,
            product_id=data.get('product_id'),
            quantity=data.get('quantity'),
            unit_price=data.get('unit_price'),
            total_price=data.get('total_price'),
            remark=data.get('remark')
        )
        db.session.add(new_detail)
        db.session.commit()

        redis_client.delete('purchases')

        return jsonify(new_detail.to_dict()), 201
    except Exception as e:
        return jsonify({'error': str(e)}), 400


@purchases_bp.route('/purchases/<int:purchase_id>/details/<int:detail_id>', methods=['PUT'])
@login_required
def update_purchase_detail(purchase_id, detail_id):
    try:
        purchase_detail = PurchaseDetail.query.filter_by(list_id=purchase_id, id=detail_id).first_or_404()
        data = request.get_json()

        new_detail_id = data.get('new_detail_id')
        if new_detail_id and new_detail_id != detail_id:
            existing_detail = PurchaseDetail.query.filter_by(id=new_detail_id).first()
            if existing_detail:
                return jsonify({'error': '新的采购明细号已存在，请选择不同的编号'}), 409  # HTTP 409 Conflict
            purchase_detail.id = new_detail_id

        purchase_detail.product_id = data.get('product_id', purchase_detail.product_id)
        purchase_detail.quantity = data.get('quantity', purchase_detail.quantity)
        purchase_detail.unit_price = data.get('unit_price', purchase_detail.unit_price)
        purchase_detail.total_price = data.get('total_price', purchase_detail.total_price)
        purchase_detail.remark = data.get('remark', purchase_detail.remark)

        db.session.commit()

        redis_client.delete('purchases')

        return jsonify(purchase_detail.to_dict()), 200
    except Exception as e:
        return jsonify({'error': str(e)}), 400


@purchases_bp.route('/purchase_details/<int:purchase_detail_id>', methods=['DELETE'])
@login_required
def delete_purchase_detail(purchase_detail_id):
    try:
        purchase_detail = PurchaseDetail.query.get_or_404(purchase_detail_id)
        db.session.delete(purchase_detail)
        db.session.commit()

        redis_client.delete('purchases')

        return jsonify({'message': '采购明细删除成功'}), 200
    except Exception as e:
        return jsonify({'error': str(e)}), 400


@purchases_bp.route('/purchases/export/csv', methods=['GET'])
@login_required
def export_purchases_csv():
    try:
        purchase_masters = PurchaseMaster.query.all()
        purchase_details = PurchaseDetail.query.all()

        output = StringIO()
        writer = csv.writer(output)

        writer.writerow(['采购清单号', '员工编号', '采购数量', '采购总价', '采购时间', '备注'])
        for master in purchase_masters:
            writer.writerow([
                master.id, master.employee_id, master.quantity, master.total_price,
                master.purchase_time.strftime('%Y-%m-%d %H:%M:%S'), master.remark
            ])

        writer.writerow([])

        writer.writerow(['采购明细号', '采购清单号', '商品编号', '采购数量', '商品单价', '商品总价', '备注'])
        for detail in purchase_details:
            writer.writerow([
                detail.id, detail.list_id, detail.product_id, detail.quantity,
                detail.unit_price, detail.total_price, detail.remark
            ])

        output.seek(0)
        return Response(
            output.getvalue(),
            mimetype='text/csv',
            headers={'Content-Disposition': 'attachment; filename=purchases.csv'}
        ), 200
    except Exception as e:
        return jsonify({'error': str(e)}), 400


@purchases_bp.route('/purchases/count', methods=['GET'])
@login_required
def get_purchase_count():
    try:
        count = PurchaseMaster.query.count()
        return jsonify({'count': count}), 200
    except Exception as e:
        return jsonify({'error': str(e)}), 400


@purchases_bp.route('/purchases/summary', methods=['GET'])
@login_required
def get_purchase_summary():
    try:
        result = db.session.execute(text('CALL get_purchase_summary()')).fetchone()
        if result:
            summary = {
                '总单数': result[0],
                '总开销': result[1]
            }
        else:
            summary = {
                '总单数': 0,
                '总开销': 0
            }
        return jsonify(summary), 200
    except Exception as e:
        print(f"Error occurred: {e}")
        return jsonify({'error': str(e)}), 400
